const jwt = require("jsonwebtoken");
const User = require("../models/userModel");
const Token = require("../models/tokenModel");
const { success, error, serverError, unauthorized, badRequest } = require('../utils/response');
const { calculateExpiry} = require('../utils/utils');
const { getLogger } = require('../logger');
const { logAudit } = require('../utils/auditLogger');
const logger = getLogger('controllers.authController');
const SSEManager = require('../utils/sseManager');
const sseManager = SSEManager.getInstance();
const UploadService = require('../services/uploadService');
const { baseurl } = require('../../config');


const logout = async (req, res) => {
    try {
        const authHeader = req.headers['authorization'];
        if (!authHeader || !authHeader.startsWith('Bearer ')) {
            return badRequest(req, res, '缺少有效的认证令牌');
        }

        const accessToken = authHeader.split(' ')[1];
        if (!accessToken) {
            return badRequest(req, res, '认证令牌格式错误');
        }

        // 从token中解析用户信息
        let userId = null;
        let username = null;
        try {
            const decoded = jwt.verify(accessToken, process.env.JWT_SECRET);
            userId = decoded.id;
            username = decoded.username;
        } catch (jwtError) {
            // 如果token已过期或无效，仍然尝试清除相关token
            logger.warn('Token解析失败，但仍尝试清除相关token', { errorMessage: jwtError.message });
        }

        // 获取token信息，包括会话ID
        let sessionId = null;
        try {
            const tokenInfo = await Token.findByToken(accessToken);
            if (tokenInfo) {
                sessionId = tokenInfo.session_id;
            }
        } catch (tokenError) {
            logger.error('获取token信息失败', { error: tokenError });
        }

        // 清除access token
        const accessTokenResult = await Token.revokeToken(accessToken);

        // 如果能够解析出用户ID，清除该用户的所有token
        if (userId) {
            try {
                // 获取登出前的token数量（用于日志）
                const activeTokenCount = await Token.getUserActiveTokenCount(userId);

                // 清除用户的所有token（包括refresh token）
                const revokedCount = await Token.revokeUserTokens(userId);

                logger.info(`用户 ${userId}(${username}) 登出，清除了 ${revokedCount} 个token（登出前有 ${activeTokenCount} 个有效token）`);
            } catch (dbError) {
                logger.error('清除用户token时出错', { error: dbError });
                // 即使清除用户token失败，也认为登出成功
            }
        }

        // 登录日志模块已移除，不再更新登录日志

        // 开发环境输出调试信息
        if (process.env.NODE_ENV === 'development') {
            logger.info(`[登出] Access Token已失效，影响行数: ${accessTokenResult}`);
        }

        await logAudit(req, { action_type: 'logout', module_code: 'login', business_type: 'logout', operation_desc: 'logout', target_entity_type: 'user', target_entity_id: userId, target_entity_name: username });
        success(req, res, '登出成功');

    } catch (err) {
        logger.error('登出错误', { error: err });
        serverError(req, res, '登出失败，请稍后重试');
    }
}


const refresh = async (req, res) => {
    try {
        const refreshTokenData = req.refreshTokenData;
        const userId = refreshTokenData.user_id;

        // 生成新的access token
        // 生成token
        const newAccessToken = jwt.sign({
            id: userId,
            username: refreshTokenData.username,
        }, process.env.JWT_SECRET, { expiresIn: '1h' }); // 1小时有效期

        const newRefreshToken = jwt.sign({
            id: userId,
            username: refreshTokenData.username,
        }, process.env.REFRESH_SECRET, { expiresIn: '7d' }); // 7天有效期

        // 计算过期时间
        const newaccessExpires = calculateExpiry('1h');
        const newrefreshExpires = calculateExpiry('7d');

        // 更新旧token
        // const updateaccessToken = await Token.revokeToken(refreshTokenData.token);

        // 写入数据库
        const createaccessToken = await Token.createToken({ user_id: userId, token: newAccessToken, token_type: 'access', expiresAt: newaccessExpires, session_id: refreshTokenData.session_id });
        const createrefreshToken = await Token.createToken({ user_id: userId, token: newRefreshToken, token_type: 'refresh', expiresAt: newrefreshExpires, session_id: refreshTokenData.session_id });

        success(req, res, 'Token刷新成功', {
            accessToken: newAccessToken,
            refreshToken: newRefreshToken,
            expiresAt: newaccessExpires
        });

    } catch (err) {
        logger.error('Token刷新错误', { error: err });
        serverError(req, res, 'Token刷新失败，请重新登录');
    }
};

// 健康检查路由
const health = async (req, res) => {
    try {
        const dbHealthy = await Token.healthCheck();
        success(req, res, '服务正常', {
            status: 'OK',
            database: dbHealthy ? 'connected' : 'disconnected',
            timestamp: new Date().toISOString()
        });
    } catch (err) {
        logger.error('数据库健康检查失败', { error: err });
        serverError(req, res, '服务异常，数据库连接失败');
    }
}

// 定时清理token
const cleanupExpiredTokens = async () => {
    try {
        const cleanedCount = await Token.cleanExpiredTokens();

        if (cleanedCount > 0) {
            logger.info(`🧹 定时清理完成，清理了 ${cleanedCount} 个过期token`);
        }

        return cleanedCount;
    } catch (error) {
        logger.error('❌ 清理过期token失败', { error });
        return 0;
    }
}



// 强制登出所有设备（清除用户所有token）
const forceLogoutAllDevices = async (req, res) => {
    try {
        const { userId } = req.params;

        if (!userId) {
            return badRequest(req, res, '用户ID不能为空');
        }

        // 获取用户信息
        const user = await User.findById(userId);
        if (!user) {
            return notFound(req, res, '用户不存在');
        }

        // 获取登出前的token数量
        const activeTokenCount = await Token.getUserActiveTokenCount(userId);

        // 清除用户的所有token
        const revokedCount = await Token.revokeUserTokens(userId);

        // 同步更新用户的所有活跃登录记录
        // 登录日志模块已移除，不再更新登录日志

        success(req, res, `已强制登出用户 ${user.username}，清除了 ${revokedCount} 个token`);
    } catch (err) {
        logger.error('强制登出错误', { error: err });
        serverError(req, res, '强制登出失败');
    }
};


// 使用sessionId强制登出用户（管理员功能）
const forceLogoutSessionuser = async (req, res) => {
    try {
        const { sessionId } = req.params;
        if (!sessionId) {
            return badRequest(req, res, '会话ID不能为空');
        }

        // 获取会话对应的用户信息
        const sessionTokens = await Token.getTokensBySessionId(sessionId);

        if (sessionTokens.length > 0) {
            // 获取第一个token的用户信息（同一session的token应该属于同一用户）
            const { user_id, username, name } = sessionTokens[0];

            // 清除用户的所有token
            const revokedCount = await Token.revokeSessionTokens(sessionId);

            // 使用SSE给用户发送登出消息
            try {
                // 确保用户ID类型与SSE管理器中一致（使用与认证中间件相同的字段名和类型）
                // 从sessionTokens中获取的user_id可能是字符串，需要转换为与SSE连接时相同的类型
                const userIdForSSE = parseInt(user_id); // 优先使用req.user.id，如果没有则尝试转换user_id

                sseManager.sendToUser(userIdForSSE, {
                    type: 'loginout',
                    data: {
                        sessionId,
                        username,
                        name,
                        timestamp: new Date().toISOString(),
                        reason: '管理员强制登出'
                    }
                });
                logger.info('已向用户发送登出消息', { userId: userIdForSSE, sessionId, username });
            } catch (sseError) {
                logger.error('发送SSE登出消息失败', { userId: user_id, sessionId, error: sseError.message });
                // SSE发送失败不影响主流程
            }

            success(req, res, `已强制登出会话 ${sessionId}，清除了 ${revokedCount} 个token，并向用户发送了登出通知`);
        } else {
            // 如果没有找到对应的token，仍然返回成功，但提示没有找到活跃token
            success(req, res, `已处理会话 ${sessionId}，但未找到关联的活跃token`);
        }
    } catch (err) {
        logger.error('强制登出会话错误', { error: err });
        serverError(req, res, '强制登出会话失败');
    }
};

// 获取用户token状态
const getUserTokenStatus = async (req, res) => {
    try {
        const { userId } = req.params;

        if (!userId) {
            return badRequest(req, res, '用户ID不能为空');
        }

        const activeTokenCount = await Token.getUserActiveTokenCount(userId);

        success(req, res, '获取用户token状态成功', {
            userId: parseInt(userId),
            activeTokenCount,
            status: activeTokenCount > 0 ? 'online' : 'offline'
        });
    } catch (err) {
        logger.error('获取用户token状态错误', { error: err });
        serverError(req, res, '获取用户token状态失败');
    }
};

// 手动清理过期token（管理员功能）
const manualCleanupTokens = async (req, res) => {
    try {
        const cleanedCount = await cleanupExpiredTokens();

        success(req, res, '手动清理完成', {
            cleanedCount,
            timestamp: new Date().toISOString()
        });
    } catch (err) {
        logger.error('手动清理token错误', { error: err });
        serverError(req, res, '手动清理失败');
    }
};

// 获取token统计信息
const getTokenStats = async (req, res) => {
    try {
        const stats = await Token.getTokenStats();

        success(req, res, '获取token统计信息成功', {
            ...stats,
            timestamp: new Date().toISOString(),
            environment: process.env.NODE_ENV || 'development',
            cleanupInterval: process.env.NODE_ENV === 'development' ? '5分钟' : '1小时'
        });
    } catch (err) {
        logger.error('获取token统计信息错误', { error: err });
        serverError(req, res, '获取统计信息失败');
    }
};


// 监控上报
const report = async (req, res) => {
    const { userId } = req.params;
    const { reportType, reportContent } = req.body;
    if (!userId) {
        return badRequest(req, res, '用户ID不能为空');
    }
    if (!reportType) {
        return badRequest(req, res, '举报类型不能为空');
    }
    if (!reportContent) {
        return badRequest(req, res, '举报内容不能为空');
    }
    try {
        const reportId = await Token.MonitorReport(userId, reportType, reportContent);
        success(req, res, '举报成功', { reportId });
    } catch (err) {
        logger.error('举报错误', { error: err });
        serverError(req, res, '举报失败');
    }
}

// 上传头像
const uploadAvatar = async (req, res) => {
    try {
        const userId = req.user.id;
        // 构建完整的URL路径
        
        // 检查文件是否已存在（由uploadService中的filename函数设置）
        if (req.fileAlreadyExists && req.existingFilePath) {

            // 使用上传的文件作为头像
            const avatarPath = `${baseurl}${req.existingFilePath}`;


            logger.info('文件已存在，直接使用已有的文件', { userId, filename: avatarPath });

            // 更新用户头像路径
            await User.updateUserAvatar(userId, avatarPath);

            return success(req, res, '头像上传成功（使用已存在文件）', {
                avatarUrl: avatarPath,
                filename: avatarPath.split('/').pop(),
                originalname: req.file?.originalname || 'avatar',
                size: 0,
                fileExists: true
            });
        }

        // 检查是否有上传的文件
        if (!req.file) {
            return badRequest(req, res, '请选择要上传的头像文件');
        }


        // 使用上传的文件作为头像
        const avatarPath = `${baseurl}${req.file.filename}`;

        // 更新用户头像路径
        await User.updateUserAvatar(userId, avatarPath);

        logger.info('头像上传成功', { userId, filename: req.file.filename });

        return success(req, res, '头像上传成功', {
            avatarUrl: avatarPath,
            filename: req.file.filename,
            originalname: req.file.originalname,
            size: req.file.size,
            fileExists: false
        });
    } catch (err) {
        logger.error('头像上传失败', { userId: req.user?.id, error: err.message });
        return serverError(req, res, '头像上传失败，请稍后重试');
    }
};

// 上传文件
const uploadFile = async (req, res) => {
    try {
        // 检查文件是否已存在
        if (req.fileAlreadyExists && req.existingFilePath) {
            const userId = req.user.id;
            const filePath = req.existingFilePath;

            logger.info('文件已存在，直接使用', { userId, filePath });

            success(req, res, '文件上传成功（使用已存在文件）', {
                fileUrl: filePath,
                filename: filePath.split('/').pop(),
                originalname: req.body.originalName || 'file',
                size: 0,
                mimetype: req.body.mimetype || 'application/octet-stream',
                fileExists: true
            });
            return;
        }

        if (!req.file) {
            return badRequest(req, res, '请选择要上传的文件');
        }

        const userId = req.user.id;
        const filePath = `/uploads/files/${req.file.filename}`;

        logger.info('文件上传成功', { userId, filename: req.file.filename, originalname: req.file.originalname });

        success(req, res, '文件上传成功', {
            fileUrl: filePath,
            filename: req.file.filename,
            originalname: req.file.originalname,
            size: req.file.size,
            mimetype: req.file.mimetype,
            fileExists: false
        });
    } catch (err) {
        logger.error('文件上传失败', { userId: req.user.id, error: err.message });
        serverError(req, res, '文件上传失败，请稍后重试');
    }
};

// 注意：合并文件切片的逻辑已移至UploadService

// 上传文件切片
const uploadLargeFile = async (req, res) => {
    try {
        const { fileHash, chunkIndex, totalChunks, filename, action } = req.body;
        const userId = req.user.id;

        // 使用UploadService验证参数
        const validation = UploadService.validateUploadParams({
            fileHash,
            chunkIndex,
            totalChunks,
            filename
        });

        if (!validation.isValid) {
            return badRequest(req, res, validation.message);
        }

        // 检查是否是最后一个切片需要合并
        if (action === 'merge' && parseInt(chunkIndex) === parseInt(totalChunks) - 1) {
            // 使用UploadService合并所有切片
            const fileUrl = await UploadService.mergeChunks(fileHash, filename, parseInt(totalChunks), userId);

            logger.info('大文件上传成功并合并', { userId, filename, fileHash });

            return success(req, res, '文件上传成功', {
                fileUrl,
                filename: `${userId}_${fileHash}_${filename}`,
                originalname: filename,
                fileHash
            });
        }

        // 单个切片上传成功
        logger.info('文件切片上传成功', { userId, fileHash, chunkIndex });
        success(req, res, '切片上传成功', {
            fileHash,
            chunkIndex,
            filename
        });
    } catch (err) {
        logger.error('大文件上传失败', { userId: req.user.id, error: err.message });
        serverError(req, res, '文件上传失败，请稍后重试');
    }
};

module.exports = {
    report,
    health,
    cleanupExpiredTokens,
    refresh,
    logout,
    forceLogoutAllDevices,
    getUserTokenStatus,
    manualCleanupTokens,
    getTokenStats,
    forceLogoutSessionuser,
    uploadAvatar,
    uploadFile,
    uploadLargeFile
};